﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="MediaDefinitionServiceTests.cs" company="DST Nexdox">
//   Copyright (c) DST Nexdox. All rights reserved.
// </copyright>
// <summary>
//   Defines the MediaDefinitionServiceTests type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace ServiceTests
{
  using System;
  using DocProcessingRepository.Interfaces;
  using Entities;
  using Exceptions;
  using FluentAssertions;
  using Moq;
  using NUnit.Framework;
  using ServiceInterfaces;
  using Services;

  [Category("Unit")]
  [TestFixture]
  public class MediaDefinitionServiceTests
  {
    private IMediaDefinitionService mediaDefinitionService;
    
    private Mock<IMediaDefinitionRepository> mediaDefinitionRepositoryMock;

    private Mock<IUserService> userServiceMock;

    private Mock<IMediaDefinitionAuditService> auditServiceMock;

    private ApplicationUser currentUser;

    [SetUp]
    public void Setup()
    {
      this.mediaDefinitionRepositoryMock = new Mock<IMediaDefinitionRepository>();
      this.userServiceMock = new Mock<IUserService>();
      this.auditServiceMock = new Mock<IMediaDefinitionAuditService>();
      this.mediaDefinitionService = new MediaDefinitionService(
        this.mediaDefinitionRepositoryMock.Object,
        this.userServiceMock.Object,
        this.auditServiceMock.Object);

      this.currentUser = new ApplicationUser("Username") { PreferredEnvironment = "Test" };
    }

    [Test]
    public void GivenAValidData_WhenITryToGetMediaDefinitions_TheMediaDefinitionsShouldBeReturned()
    {
      var mediaDefinitions = new PagedResult<MediaDefinitionEntity>();

      this.mediaDefinitionRepositoryMock.Setup(
        x => x.GetByManCoDoc(It.IsAny<Int32>(), It.IsAny<Int32>(), It.IsAny<Int32>()))
        .Returns(mediaDefinitions);

      PagedResult<MediaDefinitionEntity> returnedMediaDefinitions = this.mediaDefinitionService.GetByManCoDoc(1, 10, 1);

      this.mediaDefinitionRepositoryMock.Verify(x => x.GetByManCoDoc(It.IsAny<Int32>(), It.IsAny<Int32>(), It.IsAny<Int32>()), Times.Once);

      returnedMediaDefinitions.Should().BeSameAs(mediaDefinitions);
    }

    [Test]
    public void GivenAValidData_WhenITryToGetManCoDoc_AndDatabaseIsUnavailable_ThenADocProcessingExceptionIsReturned()
    {
      this.mediaDefinitionRepositoryMock.Setup(
        x => x.GetByManCoDoc(It.IsAny<Int32>(), It.IsAny<Int32>(), It.IsAny<Int32>()))
        .Throws<DocProcessingException>();

      Action act = () => this.mediaDefinitionService.GetByManCoDoc(1, 10, 1);

      act.ShouldThrow<DocProcessingException>();
    }

    [Test]
    public void GivenValidData_WhenIUpdateThePrintFlag_TheDatabaseIsUpdated()
    {
      this.userServiceMock.Setup(u => u.GetApplicationUser()).Returns(this.currentUser);

      this.mediaDefinitionService.UpdatePrintFlag(1, true);

      this.mediaDefinitionRepositoryMock.Verify(r => r.UpdatePrintFlag(It.IsAny<Int32>(), It.IsAny<Boolean>()), Times.Once);

      this.auditServiceMock.Verify(
        a =>
        a.AddAudit(
          1,
          this.currentUser.Id,
          MediaDefinitionAudit.MediaDefinitionAuditType.PrintFlagUpdated,
          It.IsAny<DateTime>(),
          "Print flag set as 'True'"),
        Times.Once);
    }

    [Test]
    public void GivenValidData_WhenIUpdateThePrintFlag_AndTheDatabaseIsUnavailable_ThenADocProcessingExceptionIsReturned()
    {
      this.mediaDefinitionRepositoryMock.Setup(
        x => x.UpdatePrintFlag(It.IsAny<Int32>(), It.IsAny<Boolean>()))
        .Throws<DocProcessingException>();

      Action act = () => this.mediaDefinitionService.UpdatePrintFlag(1, true);

      act.ShouldThrow<DocProcessingException>();

      this.auditServiceMock.Verify(
        a =>
        a.AddAudit(
          It.IsAny<Int32>(),
          It.IsAny<String>(),
          It.IsAny<MediaDefinitionAudit.MediaDefinitionAuditType>(),
          It.IsAny<DateTime>(),
          It.IsAny<String>()),
        Times.Never);
    }
  }
}
